package storage

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// LocalStorage 本地存储驱动
type LocalStorage struct {
	// 存储根目录
	RootPath string
	// 基础URL (用于生成访问链接)
	BaseURL string
}

// NewLocalStorage 创建本地存储驱动
func NewLocalStorage(rootPath, baseURL string) *LocalStorage {
	return &LocalStorage{
		RootPath: rootPath,
		BaseURL:  strings.TrimSuffix(baseURL, "/"),
	}
}

// Upload 上传文件
func (ls *LocalStorage) Upload(path string, file io.Reader, filename string) (string, error) {
	// 确保目录存在
	fullPath := filepath.Join(ls.RootPath, path)
	if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
		return "", fmt.Errorf("创建目录失败: %w", err)
	}

	// 创建文件
	dst, err := os.Create(fullPath)
	if err != nil {
		return "", fmt.Errorf("创建文件失败: %w", err)
	}
	defer dst.Close()

	// 复制文件内容
	if _, err := io.Copy(dst, file); err != nil {
		return "", fmt.Errorf("写入文件失败: %w", err)
	}

	// 返回访问URL
	return ls.GetURL(path), nil
}

// UploadMultipart 上传multipart文件
func (ls *LocalStorage) UploadMultipart(path string, fileHeader *multipart.FileHeader) (string, error) {
	// 打开上传的文件
	src, err := fileHeader.Open()
	if err != nil {
		return "", fmt.Errorf("打开上传文件失败: %w", err)
	}
	defer src.Close()

	// 读取文件内容并生成MD5文件名
	content, err := io.ReadAll(src)
	if err != nil {
		return "", fmt.Errorf("读取文件内容失败: %w", err)
	}

	// 使用strings.NewReader创建新的Reader
	reader := strings.NewReader(string(content))
	return ls.Upload(path, reader, fileHeader.Filename)
}

// Delete 删除文件
func (ls *LocalStorage) Delete(path string) error {
	fullPath := filepath.Join(ls.RootPath, path)
	if err := os.Remove(fullPath); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("删除文件失败: %w", err)
	}
	return nil
}

// GetURL 获取文件访问URL
func (ls *LocalStorage) GetURL(path string) string {
	// 统一使用正斜杠
	urlPath := strings.ReplaceAll(path, "\\", "/")
	return fmt.Sprintf("%s/%s", ls.BaseURL, urlPath)
}

// Exists 检查文件是否存在
func (ls *LocalStorage) Exists(path string) bool {
	fullPath := filepath.Join(ls.RootPath, path)
	_, err := os.Stat(fullPath)
	return err == nil
}

// GenerateFilename 基于文件内容生成安全的文件名
func GenerateFilename(originalName string, fileContent []byte) string {
	ext := filepath.Ext(originalName)

	// 计算文件内容的MD5哈希
	hash := md5.Sum(fileContent)
	md5Hash := fmt.Sprintf("%x", hash)

	// 生成时间戳（精确到毫秒）
	timestamp := time.Now().Format("20060102150405.000")

	// 生成4位随机字符串
	randomStr := generateRandomString(4)

	// 组合：MD5_时间戳_随机字符串.扩展名
	return fmt.Sprintf("%s_%s_%s%s", md5Hash, timestamp, randomStr, ext)
}

// GenerateSecureFilename 生成更安全的文件名（仅MD5，用于去重检查）
func GenerateSecureFilename(originalName string, fileContent []byte) string {
	ext := filepath.Ext(originalName)
	hash := md5.Sum(fileContent)
	md5Hash := fmt.Sprintf("%x", hash)
	return fmt.Sprintf("%s%s", md5Hash, ext)
}

// GenerateFilenameFromReader 从Reader生成MD5文件名
func GenerateFilenameFromReader(originalName string, reader io.Reader) (string, []byte, error) {
	// 读取文件内容
	content, err := io.ReadAll(reader)
	if err != nil {
		return "", nil, fmt.Errorf("读取文件内容失败: %w", err)
	}

	// 生成文件名
	filename := GenerateFilename(originalName, content)

	return filename, content, nil
}

// CalculateFileMD5 计算文件MD5哈希值
func CalculateFileMD5(content []byte) string {
	hash := md5.Sum(content)
	return fmt.Sprintf("%x", hash)
}

// CalculateFileSHA256 计算文件SHA256哈希值（更安全）
func CalculateFileSHA256(content []byte) string {
	hash := sha256.Sum256(content)
	return fmt.Sprintf("%x", hash)
}

// GenerateFilenameWithSHA256 使用SHA256生成文件名（推荐）
func GenerateFilenameWithSHA256(originalName string, fileContent []byte) string {
	ext := filepath.Ext(originalName)

	// 计算文件内容的SHA256哈希
	hash := sha256.Sum256(fileContent)
	sha256Hash := fmt.Sprintf("%x", hash)

	// 生成时间戳（精确到毫秒）
	timestamp := time.Now().Format("20060102150405.000")

	// 生成4位随机字符串
	randomStr := generateRandomString(4)

	// 组合：SHA256前16位_时间戳_随机字符串.扩展名
	return fmt.Sprintf("%s_%s_%s%s", sha256Hash[:16], timestamp, randomStr, ext)
}

// GenerateSecureFilenameWithSHA256 生成SHA256安全文件名（用于去重）
func GenerateSecureFilenameWithSHA256(originalName string, fileContent []byte) string {
	ext := filepath.Ext(originalName)
	hash := sha256.Sum256(fileContent)
	sha256Hash := fmt.Sprintf("%x", hash)
	// 使用SHA256前16位作为文件名（已足够唯一）
	return fmt.Sprintf("%s%s", sha256Hash[:16], ext)
}

// generateRandomString 生成随机字符串
func generateRandomString(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
	b := make([]byte, length)
	rand.Read(b)
	for i := range b {
		b[i] = charset[b[i]%byte(len(charset))]
	}
	return string(b)
}

// GeneratePath 生成存储路径
func GeneratePath(category string, filename string) string {
	now := time.Now()
	// 使用正斜杠作为路径分隔符，确保URL正确
	return fmt.Sprintf("%s/%s/%s/%s/%s",
		category,
		now.Format("2006"),
		now.Format("01"),
		now.Format("02"),
		filename)
}
